package la.iok.hzsvn.lewin.movie.operation.service;

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.common.models.AlipayTradeCancelResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeCloseResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse;
import la.iok.hzsvn.lewin.movie.core.exception.ErrorCode;
import la.iok.hzsvn.lewin.movie.operation.cfg.AliPayProperties;
import la.iok.hzsvn.lewin.movie.operation.cfg.ServerGatewayProperty;
import la.iok.hzsvn.lewin.movie.operation.entity.ChargeOrder;
import la.iok.hzsvn.lewin.movie.operation.model.ChargeOrderInfo;
import la.iok.hzsvn.share.annotations.NotNull;
import la.iok.hzsvn.share.tools.exception.SystemException;
import la.iok.hzsvn.share.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Service("aliPayService")
public class AliPayService  implements PayService, InitializingBean {
    private static final Logger logger = LoggerFactory.getLogger(AliPayService.class);
    private static final String SUCCESS = "10000"; // 成功
    private static final String PAYING  = "10003"; // 用户支付中
    private static final String FAILED  = "40004"; // 失败
    private static final String ERROR   = "20000"; // 系统异常

    private final ServerGatewayProperty serverGatewayProperty;
    @Value("${server.servlet.context-path:}")
    private String defaultContextPath;
    private final AliPayProperties aliPayProperties;

    public AliPayService(ServerGatewayProperty serverGatewayProperty,
                         AliPayProperties aliPayProperties) {
        this.serverGatewayProperty = serverGatewayProperty;
        this.aliPayProperties = aliPayProperties;
    }

    @Override
    public String prepare(@NotNull ChargeOrderInfo order) {
        try {
            AlipayTradePrecreateResponse res = Factory.Payment.FaceToFace()
                    .preCreate(order.description(), order.orderId(),order.amountStr());
            if(ResponseChecker.success(res)){
                return res.qrCode;
            }else{
                ErrorCode.PREPARE_ORDER_RES_ERROR.fail(res.msg + "," + res.subMsg);
            }
        } catch (SystemException e){
            throw e;
        } catch (Exception e) {
            ErrorCode.PREPARE_ORDER_RES_ERROR.fail("支付宝下单失败",e);
        }
        return null;
    }

    @Override
    public void closeOrder(ChargeOrderInfo order) {
        try {
            AlipayTradeCloseResponse res = Factory.Payment.Common().close(order.orderId());
            if(tradeNotExist(res)){
                AlipayTradeCancelResponse response = Factory.Payment.Common().cancel(order.orderId());
                ErrorCode.CLOSE_ORDER_ERROR.assertTrue(ResponseChecker.success(response),order.orderId(),response.msg + "," + response.subMsg);
            }else{
                ErrorCode.CLOSE_ORDER_ERROR.assertTrue(ResponseChecker.success(res),order.orderId(),res.msg + "," + res.subMsg);
            }
        } catch (Exception e) {
            logger.error("关闭订单异常",e);
        }
    }

    @Override
    public void queryOrder(ChargeOrderInfo order) {
        try {
            AlipayTradeQueryResponse res = Factory.Payment.Common().query(order.orderId());
            if(tradeNotExist(res)){
                //坑货，用户还未扫码也返回交易不存在
                return;
            }
            ErrorCode.QUERY_ORDER_ERROR.assertTrue(ResponseChecker.success(res),order.orderId(),res.msg + "," + res.subMsg);
            if(querySuccess(res)){
                logger.info("查询订单成功:状态：{},时间:{}",res.tradeStatus,res.sendPayDate);
                order.setState(ChargeOrder.STATE_PAID);
                order.setEndTime(parseTime(res.sendPayDate));
            }else if("TRADE_CLOSED".equals(res.getTradeStatus())){
                order.setState(ChargeOrder.STATE_CLOSED);
            }else if("WAIT_BUYER_PAY".equals(res.tradeStatus)){
                //待支付
            }
        }  catch (SystemException e){
            throw e;
        } catch (Exception e) {
            ErrorCode.QUERY_ORDER_ERROR.fail(order.orderId(),"支付宝订单查询失败",e);
        }
    }

    private Date parseTime(String sendPayDate) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            return sdf.parse(sendPayDate);
        } catch (ParseException e) {
            return null;
        }
    }

    // 查询返回“支付成功”
    private boolean querySuccess(AlipayTradeQueryResponse response) {
        return response != null &&
                SUCCESS.equals(response.getCode()) &&
                ("TRADE_SUCCESS".equals(response.getTradeStatus()) ||
                        "TRADE_FINISHED".equals(response.getTradeStatus())
                );
    }
    private boolean tradeNotExist(AlipayTradeCloseResponse res){
        return tradeNotExist(res.code, res.subCode);
    }
    private boolean tradeNotExist(AlipayTradeQueryResponse res){
        return tradeNotExist(res.code, res.subCode);
    }
    private boolean tradeNotExist(String code, String subCode){
        return "40004".equals(code) && "ACQ.TRADE_NOT_EXIST".equals(subCode);
    }

    @Override
    public String notify(String notification, String signature, String serialNumber, String nonce, String timestamp) {
        return null;
    }

    private String notifyUrl(){
        return String.format("%s://%s%s%s",serverGatewayProperty.getScheme(),serverGatewayProperty.hostPort(),
                StringUtils.defaultIfBlank(serverGatewayProperty.getContextPath(),defaultContextPath), "/operation/aliPay/notify");
    }

    private Config getOptions() {
        Config config = new Config();
        config.protocol = "https";
        config.gatewayHost = "openapi.alipay.com";
        config.signType = "RSA2";
        config.appId = "2021003179647139";
        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
        config.merchantPrivateKey = aliPayProperties.merchantPrivateKey();
        //注：证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径，优先从文件系统中加载，加载失败后会继续尝试从CLASS_PATH中加载
        config.merchantCertPath = aliPayProperties.merchantCertPath();// "<-- 请填写您的应用公钥证书文件路径，例如：/foo/appCertPublicKey_2019051064521003.crt -->";
        config.alipayCertPath = aliPayProperties.alipayCertPath();// "<-- 请填写您的支付宝公钥证书文件路径，例如：/foo/alipayCertPublicKey_RSA2.crt -->";
        config.alipayRootCertPath = aliPayProperties.alipayRootCertPath();// "<-- 请填写您的支付宝根证书文件路径，例如：/foo/alipayRootCert.crt -->";
        //注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可
        // config.alipayPublicKey = "<-- 请填写您的支付宝公钥，例如：MIIBIjANBg... -->";
        //可设置异步通知接收服务地址（可选）
        config.notifyUrl = notifyUrl();
        //可设置AES密钥，调用AES加解密相关接口时需要（可选）
        config.encryptKey = aliPayProperties.aesKey();
        return config;
    }

    @Override
    public void afterPropertiesSet() {
        try{
            Factory.setOptions(getOptions());
        }catch (Exception e){
            logger.error("配置支付宝失败",e);
        }
    }
}
